/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

//===========================================================================================
#include <dylab/utils/Timer.h>
#include <dylab/utils/log/Log.h>

//===========================================================================================
void dylab::Timer::reset()
{
#ifdef DYLAB_PLATFORM_WINDOWS
    QueryPerformanceFrequency(&mFrequency);
    QueryPerformanceCounter(&mStartTime);
    mStartTick = GetTickCount();
    mLastTime = 0;
    mQueryCount = 0;

    // Save the current process
    HANDLE mProc = GetCurrentProcess();

    // Get the current Affinity
    GetProcessAffinityMask(mProc, &mProcMask, &mSysMask);

    mThread = GetCurrentThread();
#endif
}
//-----------------------------------------------------------------------------
dylab::uint32_t dylab::Timer::getElapsedMicroseconds()
{
#ifdef DYLAB_PLATFORM_WINDOWS
    LARGE_INTEGER curTime;

    // Set affinity to the first core
    SetThreadAffinityMask(mThread, 1);

    // Query the performance counter
    QueryPerformanceCounter(&curTime);

    // Reset affinity
    SetThreadAffinityMask(mThread, mProcMask);

    LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;

    // get milliseconds to check against GetTickCount
    unsigned long newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);

    // detect and compensate for performance counter leaps
    // (surprisingly common, see Microsoft KB: Q274323)
    unsigned long check = GetTickCount() - mStartTick;
    signed long msecOff = (signed long)(newTicks - check);
    if (msecOff < -100 || msecOff > 100)
    {
        // We must keep the timer running forward :)
        LONGLONG adjust = (std::min)(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);
        mStartTime.QuadPart += adjust;
        newTime -= adjust;
    }

    // Record last time for adjust
    mLastTime = newTime;

    // scale by 1000000 for microseconds
    unsigned long newMicro = (unsigned long) (1000000 * newTime / mFrequency.QuadPart);

    return newMicro;
#endif
}
//-----------------------------------------------------------------------------